#ifndef __GAME_SOCKET_H__
#define __GAME_SOCKET_H__

#include "game_def.h"
#include "game_event.h"
#include <vector>
#include <string>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>

#ifndef MAX_SOCKETD_WORKERPROCESSES
#define MAX_SOCKETD_WORKERPROCESSES 1
#endif

typedef int sockfd_t;

// #if ((CGAME_TARGET_PLATFORM == CGAME_PLATFORM_LINUX) || (CGAME_TARGET_PLATFORM == CGAME_PLATFORM_MAC) || (CGAME_TARGET_PLATFORM == CGAME_PLATFORM_WIN))
// #include "platform/evsocket.h"
// #endif
class CGameSocket;
class CGameSocketd;



namespace CGame{
namespace Socket{


template <typename TYPE, void (TYPE::*onAccept)(evutil_socket_t fd, short events, void* arg)>
void __socketd_accept_cb(evutil_socket_t fd, short events, void* arg){
  TYPE* This = (TYPE*)arg;
  This->onAccept(fd,events,arg);
}


template <typename TYPE, void (TYPE::*onRead)(bufferevent* bev)>
void __socketd_read_cb(bufferevent* bev, void* arg){
  // SocketdContext_t* ctx = (SocketdContext_t*)arg;
  TYPE* This = (TYPE*)arg;
  This->onRead(bev);
}

template <typename TYPE, void (TYPE::*onEvents)(bufferevent* bev,short events)>
void __socketd_events_cb(struct bufferevent *bev, short events, void *arg){
  // SocketdContext_t* ctx = (SocketdContext_t*)arg;
  TYPE* This = (TYPE*)arg;
  This->onEvents(bev,events);
}



}}




class CGameSocketIO{
protected:
  sockfd_t _fd;
  mseconds_t _sleep = 40;
  int _port;
  std::string _addr;
  // virtual void onRead(socket_context_t *ctx) = 0;
  // virtual void onWrite(socket_context_t *ctx) = 0;
  /**
   * @brief socket 构建函数
   */
  virtual sockfd_t socket() = 0;
public:
  // virtual void run() = 0;
  virtual const char* getName() = 0;
  virtual ~CGameSocketIO();

};

class CGameSocket:public CGameSocketIO{
protected:
  int connect(sockfd_t fd,const char *addr,int port);
  BOOL _connected;
  sockfd_t socket();
  event_base* _evbase;
  /**
   * @brief bufferevent
   */
  bufferevent* _bev;

  virtual void onRead(bufferevent* bev);
  virtual void onEvents(bufferevent* bev,short events);
  virtual void onClose();


  template <typename TYPE, void (TYPE::*onRead)(bufferevent* bev)>
  friend void CGame::Socket::__socketd_read_cb(bufferevent* bev, void* arg);

  template <typename TYPE, void (TYPE::*onEvents)(bufferevent* bev,short events)>
  friend void CGame::Socket::__socketd_events_cb(struct bufferevent *bev, short events, void *arg);
public:
  CGameSocket();
  virtual ~CGameSocket();
  // BOOL init();
  virtual sockfd_t connect(const char *addr ,int port);
  virtual BOOL disconnect();
  virtual void run();
  virtual int send(const void *ptr ,int len);
  virtual const char* getName();
  virtual BOOL init();
  virtual BOOL init(event_base* evbase);
  BOOL getConnected() const{
    return _connected;
  }
};

class CGameSocketd:public CGameSocketIO{
public:

  class Connection:public CGameRef{
    private:
      template <typename TYPE, void (TYPE::*onRead)(bufferevent* bev)>
      friend void CGame::Socket::__socketd_read_cb(bufferevent* bev, void* arg);

      template <typename TYPE, void (TYPE::*onEvents)(bufferevent* bev,short events)>
      friend void CGame::Socket::__socketd_events_cb(struct bufferevent *bev, short events, void *arg);
    protected:
      sockfd_t _sockfd;
      int _remotePort;
      char* _remoteAddress;
      CGameSocketd* _socketd;
      bufferevent* _bufferevent;
      virtual void onClose();
      virtual void onError();
      virtual void onRead(bufferevent* bev);
      virtual void onEvents(bufferevent* bev,short events);
      virtual void close();
    public:
      Connection(CGameSocketd* socketd);
      virtual BOOL init(sockfd_t fd,event_base* evbase,const sockaddr_in& sa);
      virtual ~Connection();

      virtual int send(const void *ptr ,int len);
      const char* getRemoteAddress() const {
        return _remoteAddress;
      }

      int getRemotePort() const {
        return _remotePort;
      }
  };
private:
  template <typename TYPE, void (TYPE::*onAccept)(int fd, short events, void* arg) >
  friend void CGame::Socket::__socketd_accept_cb(evutil_socket_t fd, short events, void* arg);

protected:
  event_base* _evbase;
  event* _ev;
  virtual BOOL listen(sockfd_t fd,const char *addr,int port);
  virtual const char* getName();
  // virtual void onWrite(socket_context_t *ctx);
  virtual void onAccept(Connection* conn,int fd, short events, void* arg);
  virtual void onAccept(int fd, short events, void* arg);
  virtual sockfd_t socket();
public:
  CGameSocketd();
  virtual ~CGameSocketd();
  virtual BOOL init(int port);
  virtual BOOL init(const char *addr,int port);
  virtual BOOL init(event_base* evbase,const char *addr,int port);


  virtual void run();


};

#endif
